import numpy as np
import pandas as pd
from pandas import Timestamp
from model.FaultDetectionResult import FaultTypeResult
from model.FaultType import FaultType
from parser.cfg_parser import CfgParser
from utils import extract_channel_columns


class FaultStartTimeDetector:
    """故障开始时间检测器"""

    def detect(self, df: pd.DataFrame, cfg_obj: CfgParser):
        sample_rate = cfg_obj.sample_rates[0]
        frequency = cfg_obj.reference_frequency
        t_normal = Timestamp(" ".join(cfg_obj.start_time))

        channels = extract_channel_columns(df)

        # 获取正常时刻索引
        try:
            normal_index = df.index.get_indexer([t_normal], method="nearest")[0]
        except Exception:
            return FaultTypeResult(FaultType.UNKNOWN, {"error": "故障时间不在录波范围内"})

        window = int(sample_rate // frequency)
        if normal_index + window > len(df):
            return FaultTypeResult(FaultType.UNKNOWN, {"error": "正常状态窗口超出范围"})

        current_cols = [c for c in [channels.get("IA"), channels.get("IB"), channels.get("IC")] if c in df.columns]
        if not current_cols:
            return FaultTypeResult(FaultType.UNKNOWN, {"error": "未找到电流通道"})

        base_df = df.iloc[normal_index: normal_index + window]
        base_current = np.sqrt((base_df[current_cols] ** 2).mean())

        threshold_current = base_current.std() * 2

        rms_current = self.fast_rms_multi(df[current_cols], window)
        current_change = (rms_current - base_current) / base_current

        fault_mask = (current_change.abs() > threshold_current).any(axis=1)
        valid_faults = fault_mask[fault_mask == True].index

        fault_time = valid_faults[0] if len(valid_faults) > 0 else None

        return fault_time

    @staticmethod
    def fast_rms_multi(df: pd.DataFrame, window: int) -> pd.DataFrame:
        x2 = df.values ** 2
        cumsum = np.cumsum(x2, axis=0)
        sum_sq = cumsum[window:] - cumsum[:-window]
        rms = np.sqrt(sum_sq / window)
        result = pd.DataFrame(rms, index=df.index[window:], columns=df.columns)
        return result.reindex(df.index)
